/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.karol.lx.monitor;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.karol.lx.distributor.DistributingStrategy;
import org.karol.lx.distributor.GraderSelector;
import org.karol.lx.grader.StandardGraderInterface;

/**
 *
 * @author karol
 */
public class Monitor implements GraderSelector {

    private static Monitor instance = null;
    public static final int MONITORING_PERIOD = 2000;
    private Timer mMainTimer;
    protected ArrayList<MonitorListener> mListeners = new ArrayList<MonitorListener>();
    private ArrayList<StandardGraderInterface> mGraderInterfaces = null;
    private DistributingStrategy mStrategy = null;


    private Monitor() {
        mMainTimer = new Timer();
    }
    
    public void loadConfiguration(MonitorConfigurationReader pConfigurator) {
        mGraderInterfaces = pConfigurator.getRegisteredGraderInterfaces();
        mStrategy = pConfigurator.getSelectedStrategy();
    }
    
    public DistributingStrategy getStrategy() {
        return mStrategy;
    }
    
    public void prepare() {
        evaluate();
    }

    public void addListener(MonitorListener pListener) {
        mListeners.add(pListener);
    }

    public void removeListener(MonitorListener pListener) {
        mListeners.remove(pListener);
    }

    protected void notifyGraderInaccessible(StandardGraderInterface i) {
        for (MonitorListener l : mListeners) {
            l.onGraderInaccessible(i);
        }
    }

    public void main() {
        mMainTimer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                evaluate();
            }
        }, MONITORING_PERIOD, MONITORING_PERIOD);
    }

    protected void evaluate() {
        Logger.getLogger(Monitor.class.getName()).log(Level.INFO, "Evaluating system condition at " + Calendar.getInstance().getTimeInMillis());
        ///Evaluate machines
        String tStatus = "\n=================================\n";
        for (StandardGraderInterface i : mGraderInterfaces) {
            tStatus += i.getAddress();
            double tLoad = i.getActualLoadPercentage();
            if (tLoad < 0.0) { ///Unreachable, redirecting all handled requests
                tStatus += " unreachable, requeuing all handled requests ";
                i.setActive(false);
                i.requeueHandledRequests();
            } else {
                tStatus += " ok";
                i.setActive(true);
            }

            i.setLoadPercentage(tLoad);
            tStatus += " with load = " + tLoad + "%, handled request = " + i.getHandledRequests().size() + "\n";
        }
        Logger.getLogger(Monitor.class.getName()).log(Level.INFO, tStatus + "=================================\n");
    }
    
    public ArrayList<StandardGraderInterface> getGraderInterfaces() {
        return mGraderInterfaces;
    }

    public static Monitor getInstance() {
        if (instance == null) {
            instance = new Monitor();
        }
        return instance;
    }

    @Override
    public StandardGraderInterface getSelectedGrader() {
        if (mStrategy != null)
            return mStrategy.getRecommendedGrader(mGraderInterfaces);
        else
            return null;
    }

    
}
